/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
/*
* Created on Jul 1, 2006
* @author Fabio
*/
package org.python.pydev.editor.codecompletion;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.TextPresentation;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationPresenter;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.python.pydev.core.docutils.ParsingUtils;
import org.python.pydev.core.docutils.SyntaxErrorException;
import org.python.pydev.core.log.Log;
/**
* Based on JavaParameterListValidator
*
* @author Fabio
*/
public class PyContextInformationValidator implements IContextInformationValidator, IContextInformationPresenter {
public IPyCalltipsContextInformation fInformation;
public IDocument doc;
public boolean returnedFalseOnce;
private int fPosition;
/**
* IContextInformationValidator
*/
public void install(IContextInformation info, IDocument doc, int offset) {
this.returnedFalseOnce = false;
this.fInformation = (IPyCalltipsContextInformation) info;
this.doc = doc;
this.fPosition = fInformation.getShowCalltipsOffset();
}
/**
* IContextInformationPresenter
*/
public void install(IContextInformation info, ITextViewer viewer, int offset) {
install(info, viewer.getDocument(), offset);
}
/**
* @see IContextInformationValidator#isContextInformationValid(int)
*/
public boolean isContextInformationValid(int position) {
if (doc == null) {
this.returnedFalseOnce = true;
return false;
}
try {
if (position < fPosition) {
this.returnedFalseOnce = true;
return false;
}
IDocument document = doc;
IRegion line = document.getLineInformationOfOffset(fPosition);
if (position < line.getOffset() || position >= document.getLength()) {
this.returnedFalseOnce = true;
return false;
}
boolean ret = getCurrentParameter(document, fPosition, position, "(", ")", false) >= 0; //$NON-NLS-1$ //$NON-NLS-2$
if (ret == false) {
returnedFalseOnce = true;
}
return ret;
} catch (BadLocationException x) {
this.returnedFalseOnce = true;
return false;
} catch (Exception x) {
this.returnedFalseOnce = true;
Log.log(x);
return false;
}
}
//--- interface from IContextInformationPresenter
/**
* @see IContextInformationPresenter#updatePresentation(int, TextPresentation)
*/
public boolean updatePresentation(int position, TextPresentation presentation) {
return false;
}
/**
*
* @param document the document from where the contents should be gotten.
* @param start
* @param end
* @param increments this is the string that when found will increment the current parameter
* @param decrements this is the string that when found will decrement the current parameter
* @param considerNesting
* @return
* @throws BadLocationException
* @throws SyntaxErrorException
*/
public int getCurrentParameter(IDocument document, final int start, final int end, String increments,
String decrements, boolean considerNesting) throws BadLocationException, SyntaxErrorException {
Assert.isTrue((increments.length() != 0 || decrements.length() != 0) && !increments.equals(decrements));
final int NONE = 0;
final int BRACKET = 1;
final int BRACE = 2;
final int PAREN = 3;
final int ANGLE = 4;
int nestingMode = NONE;
int nestingLevel = 0;
int charCount = 0;
int offset = start;
ParsingUtils parsingUtils = ParsingUtils.create(document);
while (offset < end) {
char curr = document.getChar(offset++);
switch (curr) {
case '#':
if (offset < end) {
// '#' comment: nothing to do anymore on this line
offset = end;
}
break;
case '"':
case '\'':
int eaten = parsingUtils.eatLiterals(null, offset - 1) + 1;
if (eaten > offset) {
offset = eaten;
}
break;
case '[':
if (considerNesting) {
if (nestingMode == BRACKET || nestingMode == NONE) {
nestingMode = BRACKET;
nestingLevel++;
}
break;
}
case ']':
if (considerNesting) {
if (nestingMode == BRACKET)
if (--nestingLevel == 0)
nestingMode = NONE;
break;
}
case '(':
if (considerNesting) {
if (nestingMode == ANGLE) {
// generics heuristic failed
nestingMode = PAREN;
nestingLevel = 1;
}
if (nestingMode == PAREN || nestingMode == NONE) {
nestingMode = PAREN;
nestingLevel++;
}
break;
}
case ')':
if (considerNesting) {
if (nestingMode == PAREN)
if (--nestingLevel == 0)
nestingMode = NONE;
break;
}
case '{':
if (considerNesting) {
if (nestingMode == ANGLE) {
// generics heuristic failed
nestingMode = BRACE;
nestingLevel = 1;
}
if (nestingMode == BRACE || nestingMode == NONE) {
nestingMode = BRACE;
nestingLevel++;
}
break;
}
case '}':
if (considerNesting) {
if (nestingMode == BRACE)
if (--nestingLevel == 0)
nestingMode = NONE;
break;
}
default:
if (nestingLevel != 0)
continue;
if (increments.indexOf(curr) >= 0) {
++charCount;
}
if (decrements.indexOf(curr) >= 0) {
--charCount;
}
}
}
return charCount;
}
}